package com.foreverwin.mes.production.support;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.foreverwin.mes.common.enums.HandleEnum;
import com.foreverwin.mes.core.exception.BusinessException;
import com.foreverwin.mes.core.utils.CommonMethods;
import com.foreverwin.mes.core.utils.DateUtil;
import com.foreverwin.mes.core.utils.SpringUtil;
import com.foreverwin.mes.meapi.model.Inventory;
import com.foreverwin.mes.meapi.model.InventoryAssyData;
import com.foreverwin.mes.meapi.service.InventoryAssyDataService;
import com.foreverwin.mes.meapi.service.InventoryService;
import com.foreverwin.mes.production.constant.Constants;
import com.foreverwin.mes.production.dto.ResourceInventoryDto;
import com.foreverwin.mes.production.model.ResourceInventory;
import com.foreverwin.mes.production.model.ResourceInventoryLog;
import com.foreverwin.mes.production.service.ResourceInventoryLogService;
import com.foreverwin.mes.production.service.ResourceInventoryService;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;

import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author Ervin Chen
 * @date 2020/2/4 13:18
 * <p>
 * 上料模式二：针对奶粉，糖（非生产设备），黑白杯等
 * 1.设备不是生产设备，通过设备OPC发送点位对应到设备进行扣料
 * 2.通过设备自定义字段（可上料物料号/可上料物料组）校验上料物料是否正确
 * 3.工单开始时通过bom检验上料物料是否正确
 * 4.会进行卸料，卸料时损耗计入设备最后一个sfc的物料耗用
 */
public class ItemBatchNumberQtyLoadStrategy implements LoadStrategy {

    private InventoryAssyDataService inventoryAssyDataService;
    private InventoryService inventoryService;
    private ResourceInventoryService resourceInventoryService;
    private ResourceInventoryLogService resourceInventoryLogService;

    private ThreadLocal<List<Inventory>> localStorage = new InheritableThreadLocal<>();

    @Override
    public void initService() {
        inventoryAssyDataService = SpringUtil.getBean(InventoryAssyDataService.class);
        inventoryService = SpringUtil.getBean(InventoryService.class);
        resourceInventoryService = SpringUtil.getBean(ResourceInventoryService.class);
        resourceInventoryLogService = SpringUtil.getBean(ResourceInventoryLogService.class);
    }

    @Override
    public boolean validate(ResourceInventoryDto resourceInventoryDto) {
        String site = CommonMethods.getSite();
        String resource = resourceInventoryDto.getResrce();
        String itemBo = resourceInventoryDto.getItemBo();
        String vendorLot = resourceInventoryDto.getVendorLot();
        Double loadQty = resourceInventoryDto.getQty();

        if (StringUtils.isBlank(vendorLot)) {
            throw BusinessException.build("production.resourceInventory.batchNumberNotBlank", new String[]{});
        }
        if (StringUtils.isBlank(itemBo)) {
            throw BusinessException.build("production.resourceInventory.itemNotBlank", new String[]{});
        }
        if (loadQty == null) {
            throw BusinessException.build("production.resourceInventory.loadQtyNotBlank", new Object[]{});
        }
        if (loadQty <= 0) {
            throw BusinessException.build("production.resourceInventory.loadQtyNotValid", loadQty);
        }

        //通过设备自定义字段（可上料物料号/可上料物料组），校验上料物料是否正确
        resourceInventoryService.validateResourceLoadItem(resource, itemBo);

        //检查是否存在符合库存批次的库存
        EntityWrapper<Inventory> inventoryWrapper = new EntityWrapper<>();
        inventoryWrapper.eq("site", site)
                .gt("qty_on_hand", 0)
                .eq("item_bo", itemBo)
                .eq("status_bo", HandleEnum.STATUS.getHandle(site, Constants.INVENTORY_AVAILABLE_STATUS))
                .orderAsc(Arrays.asList("receive_date_time"));
        List<Inventory> inventories = inventoryService.listByAssyData(inventoryWrapper, Constants.VENDOR_LOT, vendorLot);
        if (inventories.isEmpty()) {
            throw BusinessException.build("production.resourceInventory.inventoryWithBatchNumberItemNotExist", vendorLot, HandleEnum.ITEM.getPart(itemBo, 1));
        }

        //检查符合条件的库存可用数量是否满足上料数量
        Double total = inventories.stream()
                .mapToDouble(inventory -> inventory.getQtyOnHand())
                .sum();
        if (loadQty > total) {
            throw BusinessException.build("production.resourceInventory.loadQtyOverQtyOnHand", loadQty, total);
        }

        //暂存库存
        localStorage.set(inventories);
        return true;
    }

    @Override
    public boolean load(ResourceInventoryDto resourceInventoryDto) {
        List<Inventory> inventories = localStorage.get();
        String resource = resourceInventoryDto.getResrce();
        String vendorLot = resourceInventoryDto.getVendorLot();
        String itemBo = resourceInventoryDto.getItemBo();
        Double loadQty = resourceInventoryDto.getQty();
        String loadMode = resourceInventoryDto.getLoadMode();
        String site = CommonMethods.getSite();
        String userBo = CommonMethods.getUserBo();

        for (Inventory inventory : inventories) {
            Date now = new Date();
            String inventoryId = inventory.getInventoryId();
            Double qtyOnHand = inventory.getQtyOnHand();
            Double qty = 0d;
            if (loadQty > qtyOnHand) {
                qty = qtyOnHand;
                loadQty = loadQty - qty;
            } else {
                qty = loadQty;
                loadQty = loadQty - qty;
            }

            //扣减库存
            reduceInventory(inventory, qty);

            //增加设备库存
            String resourceInventoryHandle = HandleEnum.RESOURCE_INVENTORY.getHandle(site, resource, itemBo, vendorLot, inventoryId);
            ResourceInventory resourceInventory = resourceInventoryService.selectById(resourceInventoryHandle);
            if (resourceInventory == null) {
                resourceInventory = new ResourceInventory();
                resourceInventory.setHandle(resourceInventoryHandle);
                resourceInventory.setSite(site);
                resourceInventory.setResrce(resource);
                resourceInventory.setInventoryId(inventoryId);
                resourceInventory.setItemBo(itemBo);
                resourceInventory.setVendorLot(vendorLot);
                resourceInventory.setOriginalQty(qty);
                resourceInventory.setQtyOnHand(qty);
                resourceInventory.setCreatedDateTime(now);
                resourceInventory.setCreateUserBo(userBo);
                resourceInventoryService.insert(resourceInventory);
            } else {
                resourceInventory.setOriginalQty(resourceInventory.getOriginalQty() + qty);
                resourceInventory.setQtyOnHand(resourceInventory.getQtyOnHand() + qty);
                resourceInventory.setUpdatedDateTime(now);
                resourceInventory.setUpdateUserBo(userBo);
                resourceInventoryService.updateById(resourceInventory);
            }

            //保存上料记录
            String resourceInventoryLogHandle = HandleEnum.RESOURCE_INVENTORY_LOG.getHandle(site, resource, itemBo, vendorLot, DateUtil.format(now));
            ResourceInventoryLog resourceInventoryLog = new ResourceInventoryLog();
            resourceInventoryLog.setHandle(resourceInventoryLogHandle);
            resourceInventoryLog.setSite(site);
            resourceInventoryLog.setResrce(resource);
            resourceInventoryLog.setItemBo(itemBo);
            resourceInventoryLog.setInventoryId(inventoryId);
            resourceInventoryLog.setVendorLot(vendorLot);
            resourceInventoryLog.setQty(qty);
            resourceInventoryLog.setLoadMode(loadMode);
            resourceInventoryLog.setCreatedDateTime(now);
            resourceInventoryLog.setCreateUserBo(userBo);
            resourceInventoryLogService.insert(resourceInventoryLog);

            if (loadQty == 0) {
                break;
            }
        }
        return true;
    }

    public boolean reduceInventory(Inventory inventory, Double qty) {
        inventory.setQtyOnHand(inventory.getQtyOnHand() - qty);
        return inventoryService.updateById(inventory);
    }
}
